/* 
 * File:   sampdmsolver.cpp
 * Author: posypkin
 *
 * Simple distributed memory solver for
 * robotic manipulator
 * 
 * Created on September 16, 2011, 1:18 PM
 */

#include <mpi.h>
#include <fstream>
#include <string>
#include <util/mplib/mpicommunicator.hpp>
#include <kernel/dmmemory/simpsched.hpp>
#include <kernel/dmmemory/bnbdmsolver.hpp>
#include <kernel/dmmemory/schedtracer.hpp>
#include <problems/pareto/multicov/multiresolver.hpp>
#include <problems/pareto/multicov/lipbounder.hpp>
#include <problems/pareto/multiopt/multidata.hpp>
#include <problems/pareto/multicov/test1.hpp>
#include <problems/pareto/multicov/multisub.hpp>
#include <problems/pareto/multicov/subbag.hpp>
#include <problems/pareto/multicov/widfirst.hpp>
#include <problems/pareto/multiopt/mpsimpbag.hpp>
#include <problems/pareto/multiopt/mboxlocsearch.hpp>
#include <problems/pareto/multiopt/mgradesc.hpp>
#include <util/ineq/foumotz.hpp>
#include <common/robot.hpp>
#include <common/robutils.hpp>
#include <common/robibounder.hpp>

#define DELT .01
#define MAXLEN 8192
#define MAXD 2

typedef double T;

T signs[MAXD];

int dim;

void setSign(char* side) {
    if (!strcmp(side, "ne")) {
        signs[0] = -1;
        signs[1] = -1;
    } else if (!strcmp(side, "nw")) {
        signs[0] = 1;
        signs[1] = -1;
    } else if (!strcmp(side, "se")) {
        signs[0] = -1;
        signs[1] = 1;
    } else if (!strcmp(side, "sw")) {
        signs[0] = 1;
        signs[1] = 1;
    }
}

void applySign(MPSimpBag<T>& bag) {
    int n = bag.size();
    for (int i = 0; i < n; i++) {
        bag[i].mCrit.mX[0] *= signs[0];
        bag[i].mCrit.mX[1] *= signs[1];
    }
}

void input(char* fname, std::string& s) {
    std::ifstream is;
    is.open(fname);
    char buf[MAXLEN];
    is.read(buf, MAXLEN);
    s.append(buf, is.gcount());
    is.close();
}

/**
 * 
 */
int main(int argc, char** argv) {

    MPI_Init(&argc, &argv);

    MpiCommunicator com;
    std::string s;
    BinarySerializer ser;
    if (com.rank() == 0) {
        if (argc != 3) {
            BNB_ERROR_REPORT("usage: probot.exe input ne|nw|se|sw");
        }
        input(argv[1], s);
        ser << s;
        for (int i = 1; i < com.size(); i++) {
            com.send(ser, i);
        }
    } else {
        com.recv(ser);
        ser >> s;
    }
    printf("%d: %s, [%s]\n", com.rank(), s.c_str(), argv[2]);
    setSign(argv[2]);
    Box<T>* bx;
    int dim;
    int nsec;
    T eps, delt = DELT;
    std::vector< RobotObjective<T> > rov;
    RobUtils<T>::fromString(s, eps, dim, nsec, rov, &bx);
    MultiData<double> md(*bx);
    for (int i = 0; i < dim; i++) {
        rov[i].setSign(signs[i]);
    }
    for (int i = 0; i < rov.size(); i++) {
        md.mCriteria.push_back(&(rov[i]));
    }
    LipBounder<double> lb(&md);
    RobIntervalBounder<double> rb(nsec, rov[0].mSections, signs);
    MultiCov<double> ml(md);
    //ml.addBounder(&lb);
    ml.addBounder(&rb);
    ml.setPrecision(eps, delt);
    MultiState< MPSimpBag < double >, SubBag<double> > ms;
    MultiResolver mr(&ms, &ml);


    SchedTracer st(1, "/tmp");
    SimpSched sched(com.size() * 8);

    //sched.setSearchStrategies(SearchStrategies::DFS, SearchStrategies::DFS);
    //sched.setSearchStrategies(SearchStrategies::WFS, SearchStrategies::WFS);

    if (com.rank() == 0) {
        MultiSub<double> sub(md.mBox.mDim, 1);
        sub.mBox = md.mBox;
        ms.mSubBag.put(sub);
    }
    BNBDmSolver sol(&com, &sched, &mr);
    //sol.setTracer(&st);
    sol.setStatsFileName("stats.txt");
    sol.solve(com.rank(), com.size());
    if (com.rank() == 0) {
        applySign(ms.mPointBag);
        printf("%s", ms.mPointBag.toString().c_str());
    }

    /*
    long long int nit = std::numeric_limits<long long>::max();
    ml.solve(ms, nit);
     */

    MPI_Finalize();
}

